package labox.innovation.gameserver.util;

import java.util.Collection;

import javolution.util.FastMap;
import javolution.util.FastMap.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import labox.innovation.config.Config;
import labox.innovation.gameserver.model.FuzeWorld;
import labox.innovation.gameserver.model.Scene;
import labox.innovation.gameserver.model.actor.L2Character;
import labox.innovation.gameserver.model.actor.instance.FuzePcInstance;
import labox.innovation.gameserver.network.clientpackets.Say2;
import labox.innovation.gameserver.network.serverpackets.CreatureSay;
import labox.innovation.gameserver.network.serverpackets.L2GameServerPacket;
import labox.innovation.gameserver.network.serverpackets.RelationChanged;

/**
 * This class ...
 * 
 * @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $
 */

public final class Broadcast {
	private static Logger _log = LoggerFactory.getLogger(Broadcast.class.getName());

	/**
	 * Send a packet to all L2PcInstance in the _KnownPlayers of the L2Character that have the Character targetted.<BR>
	 * <BR>
	 * 
	 * <B><U> Concept</U> :</B><BR>
	 * L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>.<BR>
	 * In order to inform other players of state modification on the L2Character, server just need to go through _knownPlayers to send Server->Client Packet<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packet to this L2Character (to do this use method toSelfAndKnownPlayers)</B></FONT><BR>
	 * <BR>
	 * 
	 */
	public static void toPlayersTargettingMyself(L2Character character, L2GameServerPacket mov) {
		if (_log.isDebugEnabled())
			_log.debug("players to notify:{} packet:{}", character.getKnownList().getKnownPlayers().size(), mov.getType());

		Collection<FuzePcInstance> plrs = character.getKnownList().getKnownPlayers().values();
		for (FuzePcInstance player : plrs) {
			if (player.getTarget() != character)
				continue;
			player.sendPacket(mov);
		}
	}

	/**
	 * Send a packet to all L2PcInstance in the _KnownPlayers of the L2Character.<BR>
	 * <BR>
	 * 
	 * <B><U> Concept</U> :</B><BR>
	 * L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>.<BR>
	 * In order to inform other players of state modification on the L2Character, server just need to go through _knownPlayers to send Server->Client Packet<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packet to this L2Character (to do this use method toSelfAndKnownPlayers)</B></FONT><BR>
	 * <BR>
	 * 
	 */
	public static void toKnownPlayers(L2Character character, L2GameServerPacket mov) {
		if (_log.isDebugEnabled())
			_log.debug("players to notify:{} packet:{}", character.getKnownList().getKnownPlayers().size(), mov.getType());

		Collection<FuzePcInstance> plrs = character.getKnownList().getKnownPlayers().values();
		for (FuzePcInstance player : plrs) {
			try {
				player.sendPacket(mov);
			} catch (NullPointerException e) {
			}
		}

	}

	/**
	 * Send a packet to all L2PcInstance in the _KnownPlayers (in the specified radius) of the L2Character.<BR>
	 * <BR>
	 * 
	 * <B><U> Concept</U> :</B><BR>
	 * L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>.<BR>
	 * In order to inform other players of state modification on the L2Character, server just needs to go through _knownPlayers to send Server->Client Packet and check the distance between the targets.<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packet to this L2Character (to do this use method toSelfAndKnownPlayers)</B></FONT><BR>
	 * <BR>
	 * 
	 */
	public static void toKnownPlayersInRadius(L2Character character, L2GameServerPacket mov, int radius) {
		if (radius < 0)
			radius = 1500;

		Collection<FuzePcInstance> plrs = character.getKnownList().getKnownPlayers().values();
		for (FuzePcInstance player : plrs) {
			if (character.isInsideRadius(player, radius))
				player.sendPacket(mov);
		}
	}

	/**
	 * Send a packet to all L2PcInstance in the _KnownPlayers of the L2Character and to the specified character.<BR>
	 * <BR>
	 * 
	 * <B><U> Concept</U> :</B><BR>
	 * L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>.<BR>
	 * In order to inform other players of state modification on the L2Character, server just need to go through _knownPlayers to send Server->Client Packet<BR>
	 * <BR>
	 * 
	 */
	public static void toSelfAndKnownPlayers(L2Character character, L2GameServerPacket mov) {
		if (character instanceof FuzePcInstance) {
			character.sendPacket(mov);
		}

		toKnownPlayers(character, mov);
	}

	// To improve performance we are comparing values of radius^2 instead of calculating sqrt all the time
	public static void toSelfAndKnownPlayersInRadius(L2Character character, L2GameServerPacket mov, long radiusSq) {
		if (radiusSq < 0)
			radiusSq = 360000;

		if (character instanceof FuzePcInstance)
			character.sendPacket(mov);

		Collection<FuzePcInstance> plrs = character.getKnownList().getKnownPlayers().values();

		for (FuzePcInstance player : plrs) {
			if (player != null)
				if (Util.FastDistance2D(character.getX(), character.getY(), player.getX(), player.getY()) < radiusSq)
					player.sendPacket(mov);
		}

	}

	/**
	 * Send a packet to all L2PcInstance present in the world.<BR>
	 * <BR>
	 * 
	 * <B><U> Concept</U> :</B><BR>
	 * In order to inform other players of state modification on the L2Character, server just need to go through _allPlayers to send Server->Client Packet<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packet to this L2Character (to do this use method toSelfAndKnownPlayers)</B></FONT><BR>
	 * <BR>
	 * 
	 */
	public static void toAllOnlinePlayers(L2GameServerPacket mov) {
		if (_log.isDebugEnabled())
			_log.debug("Players to notify: {} (with packet {} )", FuzeWorld.getInstance().getAllPlayersCount(), mov.getType());
		FastMap<Long, FuzePcInstance> players = FuzeWorld.getInstance().getAllPlayers();
		for (Entry<Long, FuzePcInstance> e = players.head(), n = players.tail(); (e = e.getNext()) != n;) {
			FuzePcInstance onlinePlayer = e.getValue();
			if (onlinePlayer.isOnline() == 1)
				onlinePlayer.sendPacket(mov);
		}

	}

	public static void announceToOnlinePlayers(String text) {
		CreatureSay cs = new CreatureSay(0, Say2.NOTICE_CHANNALI, "", text);
		toAllOnlinePlayers(cs);
	}

	public static void toPlayersInInstance(L2GameServerPacket mov, int instanceId) {
		FastMap<Long, FuzePcInstance> players = FuzeWorld.getInstance().getAllPlayers();
		for (Entry<Long, FuzePcInstance> e = players.head(), n = players.tail(); (e = e.getNext()) != n;) {
			FuzePcInstance onlinePlayer = e.getValue();
			if (onlinePlayer.isOnline() == 1 && onlinePlayer.getInstanceId() == instanceId)
				onlinePlayer.sendPacket(mov);

		}

	}
}
